package com.cbs.java.component.network;


import com.cbs.java.component.network.decoder.Decoder;
import com.cbs.java.component.network.decoder.TextDecoder;
import okhttp3.CacheControl;
import okhttp3.Headers;
import okhttp3.RequestBody;

import java.util.concurrent.TimeUnit;

/**
 * Created by brochexu on 9/2/14.
 */
public class Request {
    public static CacheControl DefaultCacheControl = new CacheControl.Builder()
            .maxAge(5, TimeUnit.SECONDS).build();
    protected okhttp3.Request.Builder builder = null;
    protected ResponseHandler responseHandler = null;
    protected okhttp3.Request rawRequest = null;
    protected Decoder decoder = new TextDecoder();
    protected boolean plusTranlate = true;
    protected String url = "";

    public Request(String url) {
        builder = new okhttp3.Request.Builder();
        this.url = url;
        builder.cacheControl(CacheControl.FORCE_NETWORK);
    }

    public Request(Request request) {
        this.builder = new okhttp3.Request.Builder();
        okhttp3.Request rawRequest = request.builder.build();
        this.url = request.url;
        builder.method(rawRequest.method(), rawRequest.body());
        builder.tag(rawRequest.tag());
        builder.headers(rawRequest.headers());
        builder.cacheControl(rawRequest.cacheControl());
        this.responseHandler = request.responseHandler;
        this.decoder = request.decoder;
    }

    public Request setUrl(String url) {
        this.url = url;
        return this;
    }

    /**
     * Sets the header named {@code name} to {@code value}. If this request
     * already has any headers with that name, they are all replaced.
     */
    public Request header(String name, String value) {
        builder.header(name, value);
        return this;
    }

    /**
     * Adds a header with {@code name} and {@code value}. Prefer this method for
     * multiply-valued headers like "Cookie".
     */
    public Request addHeader(String name, String value) {
        builder.addHeader(name, value);
        return this;
    }

    public Request removeHeader(String name) {
        builder.removeHeader(name);
        return this;
    }

    /**
     * Removes all headers on this builder and adds {@code headers}.
     */
    public Request headers(Headers headers) {
        builder.headers(headers);
        return this;
    }

    /**
     * Sets this request's {@code Cache-Control} header, replacing any cache
     * control headers already present. If {@code cacheControl} doesn't define
     * any directives, this clears this request's cache-control headers.
     */
    public Request cacheControl(CacheControl cacheControl) {
        builder.cacheControl(cacheControl);
        return this;
    }


    public Request get() {
        builder.get();
        return this;
    }

    public Request head() {
        builder.head();
        return this;
    }

    public Request post(RequestBody body) {
        builder.post(body);
        return this;
    }

    public Request delete() {
        builder.delete();
        return this;
    }

    public Request delete(RequestBody body) {
        builder.delete(body);
        return this;
    }

    public Request put(RequestBody body) {
        builder.put(body);
        return this;
    }

    public Request patch(RequestBody body) {
        builder.patch(body);
        return this;
    }

    /**
     * Attaches {@code tag} to the request. It can be used later to cancel the
     * request. If the tag is unspecified or null, the request is canceled by
     * using the request itself as the tag.
     */
    public Request setTag(Object tag) {
        builder.tag(tag);
        return this;
    }

    public Request setResponseHandler(ResponseHandler handler) {
        this.responseHandler = handler;
        return this;
    }

    public ResponseHandler getResponseHandler() {
        return this.responseHandler;
    }

    public Decoder getDecoder() {
        return decoder;
    }

    public Request setDecoder(Decoder decoder) {
        this.decoder = decoder;
        return this;
    }

    public boolean isPlusTranlate() {
        return plusTranlate;
    }

    public Request setPlusTranlate(boolean plusTranlate) {
        this.plusTranlate = plusTranlate;
        return this;
    }

    public okhttp3.Request build() {
        if (plusTranlate) {
            if (url.contains("+")) {
                url = url.replace("+", "%2B");
            }
        }
        builder.url(url);
        this.rawRequest = builder.build();
        return this.rawRequest;
    }

    public okhttp3.Request getRawRequest() {
        return this.rawRequest;
    }

    @Override
    protected Request clone() throws CloneNotSupportedException {
        return new Request(this);
    }
}
